// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------
// Modification history:
// feature: Support static xml filter by participant name
// feature: add qos incompatible check, and add system test case
// ------------------------------------------------------------------

#include <xmlparser/XMLParserPart.h>
#include <deps/common/TimeConversion.h>
#include <xmlparser/data/XMLWriterProxyData.h>
#include <xmlparser/data/XMLReaderProxyData.h>
#include <deps/common/IPLocator.h>
#include <xmlparser/XMLEndpointParserPart.h>

#include <xmlparser/XMLEndpointParserPart.h>
#include <tinyxml2.h>

#include <string>
#include <cstdlib>

#include <elog/Log.hpp>

namespace vbsutil {
namespace xmlparser {

using vbsutil::xmlparser::IPLocator;
using vbsutil::xmlparser::Locator_t;
using vbsutil::xmlparser::LocatorList_t;
using vbsutil::xmlparser::NO_KEY;
using vbsutil::xmlparser::octet;
using vbsutil::xmlparser::ReaderProxyDataPart;
using vbsutil::xmlparser::WITH_KEY;
using vbsutil::xmlparser::WriterProxyDataPart;
using vbsutil::xmlparser::XMLEndpointParserPart;
using vbsutil::xmlparser::XMLP_ret;
using vbsutil::xmlparser::TimeConv::MilliSeconds2Time_t;

XMLEndpointParserPart::XMLEndpointParserPart() {
    // TODO(test) Auto-generated constructor stub
}

XMLEndpointParserPart::~XMLEndpointParserPart() {
    // TODO(test) Auto-generated destructor stub
    for (std::vector<StaticRTPSParticipantInfoPart*>::iterator pit = m_RTPSParticipants.begin();
         pit != m_RTPSParticipants.end(); ++pit) {
        for (std::vector<ReaderProxyDataPart*>::iterator rit = (*pit)->m_readers.begin();
             rit != (*pit)->m_readers.end(); ++rit) {
            delete (*rit);
        }
        for (std::vector<WriterProxyDataPart*>::iterator wit = (*pit)->m_writers.begin();
             wit != (*pit)->m_writers.end(); ++wit) {
            delete (*wit);
        }

        delete (*pit);
    }
}

XMLP_ret XMLEndpointParserPart::loadXMLFile(std::string& filename) {
    std::string temp = "";
    return loadXMLFile(filename, temp);
}

XMLP_ret XMLEndpointParserPart::loadXMLFile(std::string& filename, std::string& participantName) {
    tinyxml2::XMLDocument doc;
    tinyxml2::XMLError eResult;

    if (0 == filename.rfind("data://", 0U)) {
        logDebug(XMLPARSER, filename);
        eResult = doc.Parse(filename.c_str() + 7, filename.size() - 7U);
    } else if (0 == filename.rfind("file://", 0U)) {
        logDebug(XMLPARSER, filename);
        eResult = doc.LoadFile(filename.substr(7U).c_str());
    } else {
        logDebug(XMLPARSER, "FileName: " << filename);
        eResult = doc.LoadFile(filename.c_str());
    }

    if (tinyxml2::XML_SUCCESS != eResult) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, filename << " bad file");
        return XMLP_ret::XML_ERROR;
    }

    tinyxml2::XMLNode* root = doc.FirstChildElement(xmlString::STATICDISCOVERY);
    if (!root) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, filename << " XML has errors");
        return XMLP_ret::XML_ERROR;
    }

    tinyxml2::XMLElement* xml_RTPSParticipant = root->FirstChildElement();

    while (xml_RTPSParticipant != nullptr) {
        std::string key(xml_RTPSParticipant->Name());
        if (key == xmlString::PARTICIPANT) {
            if (!participantName.empty()) {
                const tinyxml2::XMLAttribute* attrib;
                attrib = xml_RTPSParticipant->FirstAttribute();
                if (attrib && (!strcmp(attrib->Name(), "local_name"))) {
                    if (attrib->Value() != participantName) {
                        xml_RTPSParticipant = xml_RTPSParticipant->NextSiblingElement();
                        continue;
                    }
                }
            }
            StaticRTPSParticipantInfoPart* pdata = new StaticRTPSParticipantInfoPart();
            const char* local_name_tmp = xml_RTPSParticipant->Attribute("local_name");
            std::string local_name((local_name_tmp != nullptr) ? local_name_tmp : "");
            // compatible with situations where only local name or name is configured！
            if (local_name.empty()) {
                elogWarning(XMLPARSER, "Participant with empty local_name attribute.");
            } else {
                pdata->m_RTPSParticipantName = std::move(local_name);
            }
            loadXMLParticipantEndpoint(xml_RTPSParticipant, pdata);
            m_RTPSParticipants.push_back(pdata);
        }
        xml_RTPSParticipant = xml_RTPSParticipant->NextSiblingElement();
    }

    logDebug(XMLPARSER, "Finished parsing, " << m_RTPSParticipants.size() << " participants found.");
    return XMLP_ret::XML_OK;
}

XMLP_ret XMLEndpointParserPart::loadXMLNode(tinyxml2::XMLDocument& doc) {
    logDebug(XMLPARSER, "XML node");

    tinyxml2::XMLNode* root = doc.FirstChildElement(xmlString::STATICDISCOVERY);
    if (!root) {
        elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "XML node has errors");
        return XMLP_ret::XML_ERROR;
    }

    tinyxml2::XMLElement* xml_RTPSParticipant = root->FirstChildElement();

    while (xml_RTPSParticipant != nullptr) {
        std::string key(xml_RTPSParticipant->Name());
        if (key == xmlString::PARTICIPANT) {
            StaticRTPSParticipantInfoPart* pdata = new StaticRTPSParticipantInfoPart();
            const char* local_name_tmp = xml_RTPSParticipant->Attribute("local_name");
            std::string local_name((local_name_tmp != nullptr) ? local_name_tmp : "");
            // compatible with situations where only local name or name is configured！
            if (local_name.empty()) {
                elogWarning(XMLPARSER, "Participant with empty local_name attribute.");
            } else {
                pdata->m_RTPSParticipantName = std::move(local_name);
            }
            try {
                loadXMLParticipantEndpoint(xml_RTPSParticipant, pdata);
            } catch (const std::regex_error& e) {
                (void)e;
                logWarning(XMLPARSER, std::string("catch regex_error exception:") << e.what());
            }

            m_RTPSParticipants.push_back(pdata);
        }
        xml_RTPSParticipant = xml_RTPSParticipant->NextSiblingElement();
    }

    logDebug(XMLPARSER, "Finished parsing, " << m_RTPSParticipants.size() << " participants found.");
    return XMLP_ret::XML_OK;
}

void XMLEndpointParserPart::loadXMLParticipantEndpoint(tinyxml2::XMLElement* xml_endpoint,
                                                       StaticRTPSParticipantInfoPart* pdata) {
    tinyxml2::XMLNode* xml_RTPSParticipant_child = xml_endpoint;
    tinyxml2::XMLElement* element = xml_RTPSParticipant_child->FirstChildElement();

    while (element != nullptr) {
        std::string key(element->Name());
        if (key == xmlString::NAME) {
            pdata->m_RTPSParticipantName = element->GetText();
        } else if (key == xmlString::_READER) {
            if (loadXMLReaderEndpoint(element, pdata) != XMLP_ret::XML_OK) {
                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Reader Endpoint has error, ignoring");
            }
        } else if (key == xmlString::_WRITER) {
            if (loadXMLWriterEndpoint(element, pdata) != XMLP_ret::XML_OK) {
                elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Writer Endpoint has error, ignoring");
            }
        } else {
            elogError(XMLPARSER, RetCode_t::RETCODE_ERROR, "Unknown XMK tag: " << key);
        }

        element = element->NextSiblingElement();
    }
}

XMLP_ret XMLEndpointParserPart::loadXMLReaderEndpoint(tinyxml2::XMLElement* xml_endpoint,
                                                      StaticRTPSParticipantInfoPart* pdata) {
    LocatorList_t unicast_locators;
    LocatorList_t multicast_locators;

    tinyxml2::XMLNode* xml_endpoint_child = xml_endpoint;
    tinyxml2::XMLElement* element = xml_endpoint_child->FirstChildElement();

    // Parse locators first
    while (element != nullptr) {
        std::string key(element->Name());
        if (key == xmlString::UNICAST_LOCATOR) {
            Locator_t loc;
            loc.kind = 1;
            const char* address = element->Attribute(xmlString::ADDRESS);
            std::string auxString(address ? address : "");
            (void)IPLocator::setIPv4(loc, auxString);
            int port = 0;
            (void)element->QueryIntAttribute(xmlString::PORT, &port);
            loc.port = static_cast<uint16_t>(port);
            unicast_locators.push_back(loc);
        } else if (key == xmlString::MULTICAST_LOCATOR) {
            Locator_t loc;
            loc.kind = 1;
            const char* address = element->Attribute(xmlString::ADDRESS);
            std::string auxString(address ? address : "");
            (void)IPLocator::setIPv4(loc, auxString);
            int port = 0;
            (void)element->QueryIntAttribute(xmlString::PORT, &port);
            loc.port = static_cast<uint16_t>(port);
            multicast_locators.push_back(loc);
        }

        element = element->NextSiblingElement();
    }

    ReaderProxyDataPart* rdata = new ReaderProxyDataPart(unicast_locators.size(), multicast_locators.size());
    // 存储后提供给ertps使用
    rdata->unicast_locators_size = unicast_locators.size();
    rdata->multicast_locators_size = multicast_locators.size();

    xml_endpoint_child = xml_endpoint;
    element = xml_endpoint_child->FirstChildElement();

    while (element != nullptr) {
        std::string key(element->Name());
        if (key == xmlString::USER_ID) {
            int16_t id = static_cast<int16_t>(std::strtol(element->GetText(), nullptr, 10));
            //对端xml配置文件存在多个participant时，允许reader的userid相同
            if (id <= 0) {
                elogError(XMLPARSER, RetCode_t::RETCODE_OUT_OF_RESOURCES, "Repeated or negative ID in XML file");
                delete (rdata);
                return XMLP_ret::XML_ERROR;
            }
            rdata->userDefinedId(id);
        } else if (key == xmlString::ENTITY_ID) {
            int32_t id = std::strtol(element->GetText(), nullptr, 10);
            if ((id <= 0) || (m_entityIds.insert(id).second == false)) {
                elogError(XMLPARSER, RetCode_t::RETCODE_OUT_OF_RESOURCES, "Repeated or negative entityId in XML file");
                delete (rdata);
                return XMLP_ret::XML_ERROR;
            }
            octet* c = reinterpret_cast<octet*>(&id);
            rdata->guid().entityId.value[2] = c[0];
            rdata->guid().entityId.value[1] = c[1];
            rdata->guid().entityId.value[0] = c[2];
        } else if (key == xmlString::TOPIC) {  // deprecated api
            const char* topicName = element->Attribute(xmlString::NAME);
            const char* typeName = element->Attribute(xmlString::DATA_TYPE);
            const char* kind = element->Attribute(xmlString::KIND);

            rdata->topicName((topicName != nullptr) ? std::string(topicName) : std::string(""));
            rdata->typeName((topicName != nullptr) ? std::string(typeName) : std::string(""));
            std::string auxString(kind ? kind : "");
            if (auxString == xmlString::_NO_KEY) {
                rdata->topicKind(NO_KEY);
                rdata->guid().entityId.value[3] = 0x04;
            } else if (auxString == xmlString::_WITH_KEY) {
                rdata->topicKind(WITH_KEY);
                rdata->guid().entityId.value[3] = 0x07;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, topic of kind: " << auxString << " is not valid");
                delete (rdata);
                return XMLP_ret::XML_ERROR;
            }
            if ((rdata->topicName() == xmlString::VBS_UNKNOWN_STRING) ||
                (rdata->typeName() == xmlString::VBS_UNKNOWN_STRING)) {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, topic: " << rdata->topicName() << " or typeName: " << rdata->typeName()
                                                  << " undefined");
                delete (rdata);
                return XMLP_ret::XML_ERROR;
            }
        } else if (key == xmlString::TOPIC_NAME) {
            rdata->topicName() = element->GetText();
        } else if (key == xmlString::TOPIC_DATA_TYPE) {
            rdata->typeName() = element->GetText();
        } else if (key == xmlString::TOPIC_KIND) {
            std::string auxString(element->GetText());
            if (auxString == xmlString::_NO_KEY) {
                rdata->topicKind() = NO_KEY;
                rdata->guid().entityId.value[3] = 0x04;
            } else if (auxString == xmlString::_WITH_KEY) {
                rdata->topicKind() = WITH_KEY;
                rdata->guid().entityId.value[3] = 0x07;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, topic of kind: " << auxString << " is not valid");
                delete (rdata);
                return XMLP_ret::XML_ERROR;
            }
        } else if (key == xmlString::RELIABILITY_QOS) {
            std::string auxString(element->GetText());
            if (auxString == xmlString::_RELIABLE_RELIABILITY_QOS) {
                rdata->m_qos.m_reliability.kind = RELIABLE_RELIABILITY_QOS;
            } else if (auxString == xmlString::_BEST_EFFORT_RELIABILITY_QOS) {
                rdata->m_qos.m_reliability.kind = BEST_EFFORT_RELIABILITY_QOS;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, endpoint of stateKind: " << auxString << " is not valid");
                delete (rdata);
                return XMLP_ret::XML_ERROR;
            }
        } else if (key == xmlString::UNICAST_LOCATOR) {
            // Empty but necessary to avoid warning on last else
        } else if (key == xmlString::MULTICAST_LOCATOR) {
            // Empty but necessary to avoid warning on last else
        } else if (key == xmlString::DURABILITY_QOS) {
            std::string auxstring(element->GetText());
            if (auxstring == xmlString::_PERSISTENT_DURABILITY_QOS) {
                rdata->m_qos.m_durability.kind = PERSISTENT_DURABILITY_QOS;
            } else if (auxstring == xmlString::_TRANSIENT_DURABILITY_QOS) {
                rdata->m_qos.m_durability.kind = TRANSIENT_DURABILITY_QOS;
            } else if (auxstring == xmlString::_TRANSIENT_LOCAL_DURABILITY_QOS) {
                rdata->m_qos.m_durability.kind = TRANSIENT_LOCAL_DURABILITY_QOS;
            } else if (auxstring == xmlString::_VOLATILE_DURABILITY_QOS) {
                rdata->m_qos.m_durability.kind = VOLATILE_DURABILITY_QOS;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, durability of kind: " << auxstring << " is not valid");
                delete (rdata);
                return XMLP_ret::XML_ERROR;
            }
        } else if (key == xmlString::OWNERSHIP_QOS) {
            const char* ownership = element->Attribute(xmlString::KIND);
            std::string auxstring(ownership ? ownership : xmlString::OWNERSHIP_KIND_NOT_PRESENT);
            if (auxstring == xmlString::_SHARED_OWNERSHIP_QOS) {
                rdata->m_qos.m_ownership.kind = SHARED_OWNERSHIP_QOS;
            } else if (auxstring == xmlString::_EXCLUSIVE_OWNERSHIP_QOS) {
                rdata->m_qos.m_ownership.kind = EXCLUSIVE_OWNERSHIP_QOS;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, ownership of kind: " << auxstring << " is not valid");
                delete (rdata);
                return XMLP_ret::XML_ERROR;
            }
        } else if (key == xmlString::PARTITION_QOS) {
            rdata->m_qos.m_partition.push_back(element->GetText());
        } else if (key == xmlString::LIVELINESS_QOS) {
            const char* kind = element->Attribute(xmlString::KIND);
            std::string auxstring(kind ? kind : xmlString::LIVELINESS_KIND_NOT_PRESENT);
            if (auxstring == xmlString::_AUTOMATIC_LIVELINESS_QOS) {
                rdata->m_qos.m_liveliness.kind = AUTOMATIC_LIVELINESS_QOS;
            } else if (auxstring == xmlString::_MANUAL_BY_PARTICIPANT_LIVELINESS_QOS) {
                rdata->m_qos.m_liveliness.kind = MANUAL_BY_PARTICIPANT_LIVELINESS_QOS;
            } else if (auxstring == xmlString::_MANUAL_BY_TOPIC_LIVELINESS_QOS) {
                rdata->m_qos.m_liveliness.kind = MANUAL_BY_TOPIC_LIVELINESS_QOS;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, liveliness of kind: " << auxstring << " is not valid");
                delete (rdata);
                return XMLP_ret::XML_ERROR;
            }
            const char* leaseDuration_ms = element->Attribute(xmlString::LEASE_DURATION_MS);
            auxstring = std::string(leaseDuration_ms ? leaseDuration_ms : xmlString::_INF);
            if (auxstring == xmlString::_INF) {
                rdata->m_qos.m_liveliness.lease_duration = c_TimeInfinite;
            } else {
                uint32_t milliseclease = std::strtoul(auxstring.c_str(), nullptr, 10);
                rdata->m_qos.m_liveliness.lease_duration = MilliSeconds2Time_t((double_t)milliseclease).to_duration_t();
                if (milliseclease == 0) {
                    logWarning(XMLPARSER, "BAD XML:livelinessQos leaseDuration is 0");
                }
            }
        } else if (key == xmlString::DISABLE_POSITIVE_ACKS) {
            // Disable positive acks
            if (XMLP_ret::XML_OK !=
                XMLParserpart::getXMLDisablePositiveAcksQos(element, rdata->m_qos.m_disablePositiveACKs, 0)) {
                delete (rdata);
                return XMLP_ret::XML_ERROR;
            }
        } else if (key == xmlString::DEADLINE_QOS) {
            const char* period_ms = element->Attribute(xmlString::PERIOD_MS);
            std::string auxstring = std::string(period_ms ? period_ms : xmlString::_INF);
            if (auxstring == xmlString::_INF) {
                rdata->m_qos.m_deadline.period = c_TimeInfinite;
            } else {
                uint32_t milliseclease = std::strtoul(auxstring.c_str(), nullptr, 10);
                rdata->m_qos.m_deadline.period = MilliSeconds2Time_t((double_t)milliseclease).to_duration_t();
                if (milliseclease == 0) {
                    logWarning(XMLPARSER, "BAD XML:deadlineQos periodDuration is 0");
                }
            }
        } else {
            logWarning(XMLPARSER, "Unkown Endpoint-XML tag, ignoring " << key);
        }

        element = element->NextSiblingElement();
    }

    if (rdata->userDefinedId() == 0) {
        elogError(XMLPARSER, RetCode_t::RETCODE_UNSUPPORTED, "Reader XML endpoint with NO ID defined");
        delete (rdata);
        return XMLP_ret::XML_ERROR;
    }

    for (const Locator_t& loc : unicast_locators) {
        rdata->add_unicast_locator(loc);
    }

    for (const Locator_t& loc : multicast_locators) {
        rdata->add_multicast_locator(loc);
    }

    pdata->m_readers.push_back(rdata);
    return XMLP_ret::XML_OK;
}

XMLP_ret XMLEndpointParserPart::loadXMLWriterEndpoint(tinyxml2::XMLElement* xml_endpoint,
                                                      StaticRTPSParticipantInfoPart* pdata) {
    LocatorList_t unicast_locators;
    LocatorList_t multicast_locators;

    tinyxml2::XMLNode* xml_endpoint_child = xml_endpoint;
    tinyxml2::XMLElement* element = xml_endpoint_child->FirstChildElement();

    while (element != nullptr) {
        std::string key(element->Name());
        if (key == xmlString::UNICAST_LOCATOR) {
            Locator_t loc;
            loc.kind = 1;
            const char* address = element->Attribute(xmlString::ADDRESS);
            std::string auxString(address ? address : "");
            (void)IPLocator::setIPv4(loc, auxString);
            int port = 0;
            (void)element->QueryIntAttribute(xmlString::PORT, &port);
            loc.port = static_cast<uint16_t>(port);
            unicast_locators.push_back(loc);
        } else if (key == xmlString::MULTICAST_LOCATOR) {
            Locator_t loc;
            loc.kind = 1;
            const char* address = element->Attribute(xmlString::ADDRESS);
            std::string auxString(address ? address : "");
            (void)IPLocator::setIPv4(loc, auxString);
            int port = 0;
            (void)element->QueryIntAttribute(xmlString::PORT, &port);
            loc.port = static_cast<uint16_t>(port);
            multicast_locators.push_back(loc);
        }
        element = element->NextSiblingElement();
    }

    WriterProxyDataPart* wdata = new WriterProxyDataPart(unicast_locators.size(), multicast_locators.size());
    wdata->unicast_locators_size = unicast_locators.size();
    wdata->multicast_locators_size = multicast_locators.size();

    xml_endpoint_child = xml_endpoint;
    element = xml_endpoint_child->FirstChildElement();
    while (element != nullptr) {
        std::string key(element->Name());
        if (key == xmlString::USER_ID) {
            int16_t id = static_cast<int16_t>(std::strtol(element->GetText(), nullptr, 10));
            //对端xml配置文件存在多个participant时，允许writer的userid相同
            if (id <= 0) {
                elogError(XMLPARSER, RetCode_t::RETCODE_UNSUPPORTED, "Repeated or negative ID in XML file");
                delete (wdata);
                return XMLP_ret::XML_ERROR;
            }
            wdata->userDefinedId(id);
        } else if (key == xmlString::ENTITY_ID) {
            int32_t id = std::strtol(element->GetText(), nullptr, 10);
            if ((id <= 0) || (m_entityIds.insert(id).second == false)) {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER, "Repeated or negative entityId in XML file");
                delete (wdata);
                return XMLP_ret::XML_ERROR;
            }
            octet* c = reinterpret_cast<octet*>(&id);
            wdata->guid().entityId.value[2] = c[0];
            wdata->guid().entityId.value[1] = c[1];
            wdata->guid().entityId.value[0] = c[2];
        } else if (key == xmlString::TOPIC) {
            const char* topicName = element->Attribute(xmlString::NAME);
            wdata->topicName(std::string(topicName ? topicName : xmlString::VBS_UNKNOWN_STRING));
            const char* typeName = element->Attribute(xmlString::DATA_TYPE);
            wdata->typeName(std::string(typeName ? typeName : xmlString::VBS_UNKNOWN_STRING));
            const char* kind = element->Attribute(xmlString::KIND);
            std::string auxString(kind ? kind : "");
            if (auxString == xmlString::_NO_KEY) {
                wdata->topicKind(NO_KEY);
                wdata->guid().entityId.value[3] = 0x03;
            } else if (auxString == xmlString::_WITH_KEY) {
                wdata->topicKind(WITH_KEY);
                wdata->guid().entityId.value[3] = 0x02;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, topic of kind: " << auxString << " is not valid");
                delete (wdata);
                return XMLP_ret::XML_ERROR;
            }
            if (wdata->topicName() == xmlString::VBS_UNKNOWN_STRING ||
                wdata->typeName() == xmlString::VBS_UNKNOWN_STRING) {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, topic: " << wdata->topicName() << " or typeName: " << wdata->typeName()
                                                  << " undefined");
                delete (wdata);
                return XMLP_ret::XML_ERROR;
            }
        } else if (key == xmlString::TOPIC_NAME) {
            wdata->topicName(std::string(element->GetText()));
        } else if (key == xmlString::TOPIC_DATA_TYPE) {
            wdata->typeName(std::string(element->GetText()));
        } else if (key == xmlString::TOPIC_KIND) {
            std::string auxString = std::string(element->GetText());
            if (auxString == xmlString::_NO_KEY) {
                wdata->topicKind(NO_KEY);
                wdata->guid().entityId.value[3] = 0x03;
            } else if (auxString == xmlString::_WITH_KEY) {
                wdata->topicKind(WITH_KEY);
                wdata->guid().entityId.value[3] = 0x02;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, topic of kind: " << auxString << " is not valid");
                delete (wdata);
                return XMLP_ret::XML_ERROR;
            }
        } else if (key == xmlString::RELIABILITY_QOS) {
            std::string auxString = std::string(element->GetText());
            if (auxString == xmlString::_RELIABLE_RELIABILITY_QOS) {
                wdata->m_qos.m_reliability.kind = RELIABLE_RELIABILITY_QOS;
            } else if (auxString == xmlString::_BEST_EFFORT_RELIABILITY_QOS) {
                wdata->m_qos.m_reliability.kind = BEST_EFFORT_RELIABILITY_QOS;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, endpoint of stateKind: " << auxString << " is not valid");
                delete (wdata);
                return XMLP_ret::XML_ERROR;
            }
        } else if (key == xmlString::UNICAST_LOCATOR) {
            // Empty but necessary to avoid warning on last else
        } else if (key == xmlString::MULTICAST_LOCATOR) {
            // Empty but necessary to avoid warning on last else
        } else if (key == xmlString::DURABILITY_QOS) {
            std::string auxstring = std::string(element->GetText());
            if (auxstring == xmlString::_PERSISTENT_DURABILITY_QOS) {
                wdata->m_qos.m_durability.kind = PERSISTENT_DURABILITY_QOS;
            } else if (auxstring == xmlString::_TRANSIENT_DURABILITY_QOS) {
                wdata->m_qos.m_durability.kind = TRANSIENT_DURABILITY_QOS;
            } else if (auxstring == xmlString::_TRANSIENT_LOCAL_DURABILITY_QOS) {
                wdata->m_qos.m_durability.kind = TRANSIENT_LOCAL_DURABILITY_QOS;
            } else if (auxstring == xmlString::_VOLATILE_DURABILITY_QOS) {
                wdata->m_qos.m_durability.kind = VOLATILE_DURABILITY_QOS;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, durability of kind: " << auxstring << " is not valid");
                delete (wdata);
                return XMLP_ret::XML_ERROR;
            }
        } else if (key == xmlString::OWNERSHIP_QOS) {
            const char* kind = element->Attribute(xmlString::KIND);
            std::string auxstring(kind ? kind : xmlString::OWNERSHIP_KIND_NOT_PRESENT);
            if (auxstring == xmlString::_SHARED_OWNERSHIP_QOS) {
                wdata->m_qos.m_ownership.kind = SHARED_OWNERSHIP_QOS;
            } else if (auxstring == xmlString::_EXCLUSIVE_OWNERSHIP_QOS) {
                wdata->m_qos.m_ownership.kind = EXCLUSIVE_OWNERSHIP_QOS;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, ownership of kind: " << auxstring << " is not valid");
                delete (wdata);
                return XMLP_ret::XML_ERROR;
            }
            int strength = 0;
            (void)element->QueryIntAttribute(xmlString::STRENGTH, &strength);
            wdata->m_qos.m_ownershipStrength.value = strength;
        } else if (key == xmlString::PARTITION_QOS) {
            wdata->m_qos.m_partition.push_back(element->GetText());
        } else if (key == xmlString::LIVELINESS_QOS) {
            const char* kind = element->Attribute(xmlString::KIND);
            std::string auxstring(kind ? kind : xmlString::LIVELINESS_KIND_NOT_PRESENT);
            if (auxstring == xmlString::_AUTOMATIC_LIVELINESS_QOS) {
                wdata->m_qos.m_liveliness.kind = AUTOMATIC_LIVELINESS_QOS;
            } else if (auxstring == xmlString::_MANUAL_BY_PARTICIPANT_LIVELINESS_QOS) {
                wdata->m_qos.m_liveliness.kind = MANUAL_BY_PARTICIPANT_LIVELINESS_QOS;
            } else if (auxstring == xmlString::_MANUAL_BY_TOPIC_LIVELINESS_QOS) {
                wdata->m_qos.m_liveliness.kind = MANUAL_BY_TOPIC_LIVELINESS_QOS;
            } else {
                elogError(XMLPARSER, RetCode_t::RETCODE_BAD_PARAMETER,
                          "Bad XML file, liveliness of kind: " << auxstring << " is not valid");
                delete (wdata);
                return XMLP_ret::XML_ERROR;
            }
            const char* leaseDuration_ms = element->Attribute(xmlString::LEASE_DURATION_MS);
            auxstring = std::string(leaseDuration_ms ? leaseDuration_ms : xmlString::_INF);
            if (auxstring == xmlString::_INF) {
                wdata->m_qos.m_liveliness.lease_duration = c_TimeInfinite;
            } else {
                uint32_t milliseclease = std::strtoul(auxstring.c_str(), nullptr, 10);
                wdata->m_qos.m_liveliness.lease_duration = MilliSeconds2Time_t((double_t)milliseclease).to_duration_t();
                if (milliseclease == 0) {
                    logWarning(XMLPARSER, "BAD XML:livelinessQos leaseDuration is 0");
                }
            }
        } else if (key == xmlString::DISABLE_POSITIVE_ACKS) {
            // Disable positive acks
            if (XMLP_ret::XML_OK != vbsutil::xmlparser::XMLParserpart::getXMLDisablePositiveAcksQos(
                                        element, wdata->m_qos.m_disablePositiveACKs, 0)) {
                delete (wdata);
                return XMLP_ret::XML_ERROR;
            }
        } else if (key == xmlString::DEADLINE_QOS) {
            const char* period_ms = element->Attribute(xmlString::PERIOD_MS);
            std::string auxstring = std::string(period_ms ? period_ms : xmlString::_INF);
            if (auxstring == xmlString::_INF) {
                wdata->m_qos.m_deadline.period = c_TimeInfinite;
            } else {
                uint32_t milliseclease = std::strtoul(auxstring.c_str(), nullptr, 10);
                wdata->m_qos.m_deadline.period = MilliSeconds2Time_t((double_t)milliseclease).to_duration_t();
                if (milliseclease == 0) {
                    logWarning(XMLPARSER, "BAD XML:deadlineQos periodDuration is 0");
                }
            }
        } else {
            logWarning(XMLPARSER, "Unkown Endpoint-XML tag, ignoring " << key);
        }

        element = element->NextSiblingElement();
    }

    if (wdata->userDefinedId() == 0) {
        elogError(XMLPARSER, RetCode_t::RETCODE_UNSUPPORTED, "Writer XML endpoint with NO ID defined");
        delete (wdata);
        return XMLP_ret::XML_ERROR;
    }

    for (const Locator_t& loc : unicast_locators) {
        wdata->add_unicast_locator(loc);
    }

    for (const Locator_t& loc : multicast_locators) {
        wdata->add_multicast_locator(loc);
    }

    pdata->m_writers.push_back(wdata);
    return XMLP_ret::XML_OK;
}

}  // namespace xmlparser
}  // namespace vbsutil
